#include "mapaesferico.h"
#include "ciudad.h"
#include "Territorio.h"
#include <gtkmm.h>
#include <gtkglmm.h>
#include <cmath>
#include <map>
#include <sstream>

#define TWOPI (2 * PI)
#define RADIO_CIUDAD (0.03f)
#define ALTURA_CIUDAD (0.01f)

using namespace std;

namespace ui {
namespace tablero {
namespace mapa {

MapaEsferico::MapaEsferico(TexturaDeFondo &p_TexturaDeFondo, Mapa *p_Mapa) :
	MapaAbstracto(p_TexturaDeFondo, p_Mapa),
	alpha(0.0f),
	beta(0.0f),
	dist(4.0f) {
}

MapaEsferico::~MapaEsferico() {
}

void MapaEsferico::dibujarPlaneta() {

	GLUquadricObj* qobj = gluNewQuadric();

	glEnable(GL_NORMALIZE);
	glEnable(GL_DEPTH_TEST);

	gluQuadricOrientation(qobj, GLU_OUTSIDE);
	gluQuadricDrawStyle(qobj, GLU_FILL);
	gluQuadricNormals(qobj, GLU_SMOOTH);
	gluQuadricTexture(qobj, GL_TRUE);

	glEnable(GL_TEXTURE_2D);
	glMatrixMode(GL_MODELVIEW);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(255.0f, 255.0f, 255.0f);
	this->createSphere(1.0, 64);
	glDisable(GL_TEXTURE_2D); 
	
	estrellas.dibujar();
}

void MapaEsferico::dibujarCiudades() {

	GLUquadric *t_pCiudadQuad = gluNewQuadric();

	map<string, Continente*> *continentes = this->m_Mapa->obtenerContinentes();
	map<string, Continente*>::iterator itContinentes;
	
	for ( itContinentes = continentes->begin() ; itContinentes != continentes->end(); itContinentes++ ){

		Continente *c = (*itContinentes).second;
		map<string, Territorio*> *territorios = c->getTerritorios();
		map<string, Territorio*>::iterator itTerritorios;

		for ( itTerritorios = territorios->begin() ; itTerritorios != territorios->end(); itTerritorios++ ){
			Territorio *t = (*itTerritorios).second;
		
			glPushMatrix();

			Ciudad t_Ciudad(*t, this->m_TexturaDeFondo);
			glRotated(t_Ciudad.getU2D() * 2 * 180, 0.0, 0.0, 1.0);
			glRotated(t_Ciudad.getV2D() * 180, 0.0, 1.0, 0.0);
			glTranslatef(0.0, 0.0, 1.0);
	
			gluQuadricDrawStyle(t_pCiudadQuad, GLU_FILL); 
			this->seleccionarColorDelTerritorio(*t);
			gluCylinder(t_pCiudadQuad, RADIO_CIUDAD, 0.0f, ALTURA_CIUDAD, 20, 20);

			ostringstream t_ossCantEjercitos;
			if(t->getCantidadDeEjercitos() != 0){
				t_ossCantEjercitos << t->getCantidadDeEjercitos();
				escribir(0.06f, 0.0f, 0.0f, t_ossCantEjercitos.str());
			}
			glPopMatrix();

		}
	}

	gluDeleteQuadric(t_pCiudadQuad);
}

void MapaEsferico::actualizarPerspectiva(int p_iAncho, int p_iAltura) {

	this->m_iAncho = p_iAncho;
	this->m_iAltura = p_iAltura;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f, static_cast<GLfloat>(this->m_iAncho) / static_cast<GLfloat>(this->m_iAltura), 0.1f, 100.0f);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void MapaEsferico::actualizarCamara() {

	alpha = (alpha > 2 * PI) ? alpha - 2 * PI : alpha;
	alpha = (alpha < -2 * PI) ? alpha +  2 * PI : alpha;
	beta = (beta > 1.0) ? 1.0 : beta;
	beta = (beta < -1.0) ? -1.0 : beta;
	if (dist <= 2.0) dist = 2.0;
	if (dist >= 10.0) dist = 10.0;

	viewpoint.x = dist * cos(alpha) * cos(beta);
	viewpoint.y = dist * sin(alpha) * cos(beta);
	viewpoint.z = dist * sin(beta);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(viewpoint.x, viewpoint.y, viewpoint.z,
		0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
	this->dibujar();
}

void MapaEsferico::actualizarSeleccion(int p_x, int p_y) {

	double mm[16], pm[16];
	int v[4];
	Point3 fp, np;
	Vector3 rayDir;

	this->m_fMouseX = p_x;
	this->m_fMouseY =  this->m_iAltura - p_y;

	glGetDoublev(GL_MODELVIEW_MATRIX, mm);
	glGetDoublev(GL_PROJECTION_MATRIX, pm);
	glGetIntegerv(GL_VIEWPORT, v);

	gluUnProject(this->m_fMouseX, this->m_fMouseY, 1.0, mm, pm, v, &fp.x, &fp.y, &fp.z);
	gluUnProject(this->m_fMouseX, this->m_fMouseY, 0.0, mm, pm, v, &np.x, &np.y, &np.z);
	rayDir.x = fp.x - np.x;
	rayDir.y = fp.y - np.y;
	rayDir.z = fp.z - np.z;

	this->setTerritorioSeleccionado(NULL);

	map<string, Continente*> *continentes = this->m_Mapa->obtenerContinentes();
	map<string, Continente*>::iterator itContinentes;
	
	for ( itContinentes = continentes->begin() ; itContinentes != continentes->end(); itContinentes++ ){

		Continente *c = (*itContinentes).second;
		map<string, Territorio*> *territorios = c->getTerritorios();
		map<string, Territorio*>::iterator itTerritorios;

		for (itTerritorios = territorios->begin(); itTerritorios != territorios->end(); itTerritorios++) {
		
			Territorio *t = (*itTerritorios).second;

			if (cityRayIntersection(Ciudad(*t, this->m_TexturaDeFondo), viewpoint, rayDir)) {
				this->setTerritorioSeleccionado(&(*t));
				this->dibujar();
				break;
			}
		}
	}
}

bool MapaEsferico::cityRayIntersection(const Ciudad& city, Point3 rayStart, Vector3 rayDir) {

	Point3 cityBase;
	Vector3 cityAxis;
	Plane bot, top;
	double in, out;
	int dummy;

	cityBase.x = sin((city.getV2D()) * PI) * cos((city.getU2D() * 2) * PI);
	cityBase.y = sin((city.getV2D()) * PI) * sin((city.getU2D() * 2) * PI);
	cityBase.z = cos((city.getV2D()) * PI);

	cityAxis = cityBase;
	V3Normalize(&cityAxis);

	V3Normalize(&rayDir);

	if (!intcyl(&rayStart, &rayDir, &cityBase, &cityAxis, RADIO_CIUDAD, &in, &out))
		return 0;

	bot.a = -cityAxis.x;
	bot.b = -cityAxis.y;
	bot.c = -cityAxis.z;
	bot.d = 1.0;
	top.a = cityAxis.x;
	top.b = cityAxis.y;
	top.c = cityAxis.z;
	top.d = -1.0 - ALTURA_CIUDAD;

	return clipobj(&rayStart, &rayDir, &bot, &top, &in, &out, &dummy, &dummy);
}

void MapaEsferico::createSphere(double r, int n) {

	int i, j;
	double theta1,theta2,theta3;
	Point3 e,p;
	Point3 c = {0.0f, 0.0f, 0.0f};

   for (j=0;j<n/2;j++) {
      theta1 = j * TWOPI / n; //- PID2;
      theta2 = (j + 1) * TWOPI / n; //- PID2;

      glBegin(GL_QUAD_STRIP);
      for (i=0;i<=n;i++) {
         theta3 = i * TWOPI / n;

         e.x = sin(theta2) * cos(theta3); //e.x = cos(theta2) * cos(theta3);
         e.y = sin(theta2) * sin(theta3); //e.y = sin(theta2);
         e.z = cos(theta2); //e.z = cos(theta2) * sin(theta3);

         p.x = c.x + r * e.x;
         p.y = c.y + r * e.y;
         p.z = c.z + r * e.z;

         glNormal3f(e.x,e.y,e.z);
         glTexCoord2f(i/(double)n,2*(j+1)/(double)n);
         glVertex3f(p.x,p.y,p.z);

         e.x = sin(theta1) * cos(theta3); //e.x = cos(theta1) * cos(theta3);
         e.y = sin(theta1) * sin(theta3); //e.y = sin(theta1);
         e.z = cos(theta1); //e.z = cos(theta1) * sin(theta3);
         p.x = c.x + r * e.x;
         p.y = c.y + r * e.y;
         p.z = c.z + r * e.z;

         glNormal3f(e.x,e.y,e.z);
         glTexCoord2f(i/(double)n,2*j/(double)n);
         glVertex3f(p.x,p.y,p.z);
      }
      glEnd();
   }
}

void MapaEsferico::moverCamara(mover_camara_e p_eMoverCamara) {
	
	float desplazamiento = 0.005;
	
	switch (p_eMoverCamara) {
		case MOVER_CAMARA_IZQUIERDA:
			alpha += desplazamiento; break;
		case MOVER_CAMARA_DERECHA:
			alpha -= desplazamiento; break;
		case MOVER_CAMARA_ARRIBA:
			beta -= desplazamiento; break;
		case MOVER_CAMARA_ABAJO:
			beta += desplazamiento; break;
		case MOVER_CAMARA_ATRAS:
			dist += desplazamiento; break;
		case MOVER_CAMARA_ADELANTE:
			dist -= desplazamiento; break;
	}
}

}
}
}

